﻿namespace MyWebLog.Controllers
{
    using DatabaseAbstraction.Interfaces;
    using DatabaseAbstraction.Utils;
    using MyWebLog.Logic.Models;
    using MyWebLog.Logic.Models.Security;
    using MyWebLog.Logic.Services;
    using MyWebLog.Models;
    using MyWebLog.Models.UI;
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Web.Mvc;

    /// <summary>
    /// This controller is a base for all My WebLog controllers
    /// </summary>
    public abstract class MyWebLogController : Controller
    {
        #region Multi-Blog Support

        private static List<Blog> _blogs;

        /// <summary>
        /// Blogs served by this instance of My WebLog
        /// </summary>
        public static List<Blog> Blogs
        {
            get
            {
                // Lazy initialization FTW!
                if (null == _blogs)
                    using (var data = NewDataConnection())
                        _blogs = new BlogService(data).GetAllBlogs();

                return _blogs;
            }
        }

        #endregion

        #region Session Properties

        /// <summary>
        /// The current blog
        /// </summary>
        /// <exception cref="KeyNotFoundException">
        /// If no blog instance matches the current URL
        /// </exception>
        protected Blog CurrentBlog
        {
            get
            {
                var blog = Session[SessionKey.BLOG] as Blog;

                if (null != blog)
                {
                    if (Request.Url.ToString().StartsWith(blog.BaseURL))
                        return blog;

                    // The session blog isn't the current one
                    Session[SessionKey.BLOG] = null;
                }

                var blogs = from theBlog in Blogs
                            where Request.Url.ToString().StartsWith(theBlog.BaseURL)
                            select theBlog;

                if (0 == blogs.Count())
                    throw new KeyNotFoundException("No matching blog found!");

                Session[SessionKey.BLOG] = blogs.ElementAt(0);
                return blogs.ElementAt(0);
            }
        }

        /// <summary>
        /// The current blog authorization (blog / user / permission)
        /// </summary>
        protected BlogAuthorization CurrentAuthorization
        {
            get
            {
                return Session[SessionKey.AUTHORIZATION] as BlogAuthorization;
            }
            set
            {
                Session[SessionKey.AUTHORIZATION] = value;
            }
        }

        #endregion

        #region Controller Properties

        /// <summary>
        /// Messages to be displayed to the user on the next page load
        /// </summary>
        protected IList<UserMessage> Messages { get; set; }

        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        public MyWebLogController()
        {
            Messages = new List<UserMessage>();
        }

        #region View Rendering

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <returns>
        /// The default view for the action
        /// </returns>
        protected ViewResult MyWebLogView()
        {
            SetCommonInView();
            return View();
        }

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <param name="view">
        /// The name of the view to render
        /// </param>
        /// <returns>
        /// The view
        /// </returns>
        protected ViewResult MyWebLogView(string view)
        {
            SetCommonInView();
            return View(view);
        }

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <param name="model">
        /// The model to use in rendering the view
        /// </param>
        /// <returns>
        /// The default view for the action, rendered with the specified model
        /// </returns>
        protected ViewResult MyWebLogView(object model)
        {
            SetCommonInView();
            return View(model);
        }

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <param name="view">
        /// The name of the view to render
        /// </param>
        /// <param name="model">
        /// The model to use in rendering the view
        /// </param>
        /// <returns>
        /// The view
        /// </returns>
        protected ViewResult MyWebLogView(string view, object model)
        {
            SetCommonInView();
            return View(view, model);
        }

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <param name="view">
        /// The name of the view to render
        /// </param>
        /// <param name="layout">
        /// The name of the layout file to use (overrides ViewStart)
        /// </param>
        /// <returns>
        /// The view
        /// </returns>
        protected ViewResult PrayerTrackerView(string view, string layout)
        {
            SetCommonInView();
            return View(view, layout);
        }

        /// <summary>
        /// Return a view with common information appended
        /// </summary>
        /// <param name="view">
        /// The name of the view to render
        /// </param>
        /// <param name="layout">
        /// The name of the layout file to use (overrides ViewStart)
        /// </param>
        /// <param name="model">
        /// The model to use in rendering the view
        /// </param>
        /// <returns>
        /// The view
        /// </returns>
        protected ViewResult MyWebLogView(string view, string layout, object model)
        {
            SetCommonInView();
            return View(view, layout, model);
        }

        /// <summary>
        /// Put common information in the ViewBag object
        /// </summary>
        protected void SetCommonInView()
        {
            ViewBag.Blog = CurrentBlog;
            ViewBag.Authorization = CurrentAuthorization;
            ViewBag.Version = Version();
        }

        #endregion

        #region Support

        /// <summary>
        /// Obtain a new connection to the data store
        /// </summary>
        /// <returns>
        /// A new connection to the data store
        /// </returns>
        public static IDatabaseService NewDataConnection()
        {
            var connection = ConfigurationManager.ConnectionStrings["MyWebLog"];
            return DbUtils.CreateDatabaseService(connection.ConnectionString, connection.ProviderName);
        }

        /// <summary>
        /// Get the version of MyWebLog
        /// </summary>
        /// <returns>
        /// The version (long for debug, short for release)
        /// </returns>
        public static string Version()
        {
            var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

#if (DEBUG)
            return String.Format("v{0}", version);
#else
            return String.Format("v{0}.{1}", version.Major, version.Minor);
#endif
        }

        #endregion
    }
}